(function (angular) {
    'use strict';
    var dialogModule = angular.module('fs.dialog');
    dialogModule.provider('modalService', modalServiceProvider);

    modalServiceProvider.$inject = [];
    function modalServiceProvider() {
        var provider = this;
        provider.dialogsModules = {};
        provider.loadingCount = 0;
        provider.loadingInstance = null;
        provider.loadingOptions = {
            // windowTemplateUrl : 'uib/template/modal/window.html',
            template: '<div class="icon-loading"></div>\n',
            size: 'sm',
            backdrop: 'static',
            keyboard: false,
            animation: false
        };
        provider.setDialogsModule = function (name, options) {
            provider.dialogsModules[name] = options;
        };
        provider.modalOptions = {
            size: 'lg',
            level: 'info',
            blocked: false,
            backdrop: 'static',
            keyboard: true,
            animation: true
            // windowTemplateUrl : 'fs/template/modal/window.html',
            // appendTo : provider.appendTo,
            // scope : provider.scope
            // backdropClass: '',
            // controller: '',
            // controllerAs: '',
            // openedClass:'',
            // resolve:{},
            // template: '',
            // templateUrl: '',
            // windowClass: '',
            // resolve : object or function
        };
        provider.$get = modalService;
        modalService.$inject = ['$rootScope', '$uibModal', '$uibPosition', '$window', '$document', '$q', '$log', '$timeout', 'routerService', 'hotkeys'];
        function modalService($rootScope, $uibModal, $uibPosition, $window, $document, $q, $log, $timeout, routerService, hotkeys) {
            provider.modalOptions.scope = $rootScope;
            provider.modalOptions.appendTo = angular.element($document[0].querySelector('.modal-container'));
            function moveToCenter() {
                var modalElements = $document[0].querySelectorAll('.dialogModal'), modal, top, left;
                angular.forEach(modalElements, function (modalElement) {
                    var modalContent, css = {};
                    move(1);
                    function move(count) {
                        modalContent = modalElement.querySelector('.modal-content');
                        top = ($window.innerHeight - modalElement.offsetHeight) * 2 / 5 / $window.innerHeight * 100;
                        left = ($window.innerWidth - modalElement.offsetWidth) / 2 / $window.innerWidth * 100;
                        if (top == 0 || !modalContent) {
                            if (count <= 20) {
                                $timeout(function () {
                                    move(++count);
                                }, 10, false);
                            }
                            return;
                        }
                        if (top <= 0) {
                            css.top = '30px';
                        } else {
                            css.top = top + '%';
                        }
                        if (left > 0) {
                            css.left = left + '%';
                        }
                        modal = angular.element(modalElement);
                        modal.css(css);
                    }
                });
            }

            function openLoading() {
                if (!provider.loadingInstance) {
                    provider.loadingOptions.appendTo = angular.element($document[0].querySelector('.modal-container'));
                    provider.loadingInstance = openModalDialogs(provider.loadingOptions);
                    provider.loadingInstance.closed.then(function (arg) {
                        provider.loadingInstance = null;
                        provider.loadingCount = 0;
                    });
                    ++provider.loadingCount;
                } else {
                    ++provider.loadingCount;
                }
            }

            function closeLoading() {
                if (provider.loadingInstance) {
                    --provider.loadingCount;
                    if (provider.loadingCount <= 0 && !provider.loadingInstance._closing) {
                        provider.loadingInstance.close();
                    }
                }
            }

            function openModalDialogs(modalOptions) {
                var dialogsInstance, modalOpener;
                hotkeys.pause(true);
                modalOptions.backdrop = !modalOptions.backdrop ? 'static' : modalOptions.backdrop;
                dialogsInstance = $uibModal.open(modalOptions);
                dialogsInstance.closed.then(function (arg) {
                    modalOpener = $document[0].activeElement;
                    hotkeys.unpause(true);
                    if (modalOpener && modalOpener.blur) {
                        modalOpener.blur();
                    }
                });
                dialogsInstance.rendered.then(function () {
                    var modalBackdrop = $document[0].querySelector('modal-backdrop');
                    if (modalBackdrop) {
                        modalBackdrop = angular.element(modalBackdrop);
                        modalBackdrop.css({
                            'z-index': modalBackdrop.css('z-index') - 10
                        });
                    }
                    moveToCenter();
                }, angular.noop);
                return dialogsInstance;
            }
            function openDialogs(modalOptions) {
                var dialogsInstance;
                hotkeys.pause(true);
                if (modalOptions.blocked == true) {
                    modalOptions.backdrop = !modalOptions.backdrop ? 'static' : modalOptions.backdrop;
                } else {
                    modalOptions.backdrop = false;
                }
                dialogsInstance = $uibModal.open(modalOptions);
                dialogsInstance.closed.then(function (arg) {
                    var modalOpener = $document[0].activeElement;
                    hotkeys.unpause(true);
                    if (modalOpener && modalOpener.blur) {
                        modalOpener.blur();
                    }
                });
                dialogsInstance.rendered.then(moveToCenter, angular.noop);
                return dialogsInstance;
            }
            function openWarningDialogs(options) {
                var dialogsInstance, modalOptions, defaultOption;
                options.title = options.title || 'title.dialogs.warning';
                options.level = options.level || 'warning';
                options.icon = options.icon || 'warning';
                options.messages = options.messages || [];
                defaultOption = {
                    templateUrl: options.templateUrl || 'fs/template/modal/messages.html',
                    controller: 'messageDialogsController',
                    controllerAs: 'vm',
                    windowTopClass: options.windowTopClass,
                    animation: options.animation === undefined ? true : options.animation,
                    resolve: {
                        dialogsOptions: function () {
                            return options;
                        }
                    }
                };
                modalOptions = angular.extend({}, provider.modalOptions, defaultOption);
                modalOptions.size = options.size || [600, 120];
                modalOptions.blocked = options.blocked;
                if (modalOptions.size && angular.isArray(modalOptions.size)) {
                    options.bodyStyle = {
                        width: modalOptions.size[0] + 'px',
                        height: modalOptions.size[1] + 'px'
                    };
                }
                dialogsInstance = openDialogs(modalOptions);
                return dialogsInstance;
            }
            function openAcknowledgeDialogs(options) {
                var dialogsInstance, modalOptions, defaultOption = {
                    templateUrl: options.templateUrl || 'fs/template/modal/acknowledge.html',
                    controller: 'messageDialogsController',
                    controllerAs: 'vm',
                    windowTopClass: options.windowTopClass,
                    animation: options.animation === undefined ? true : options.animation,
                    resolve: {
                        dialogsOptions: function () {
                            return options;
                        }
                    }
                };
                options.title = options.title || 'title.dialogs.acknowledge';
                options.messages = options.messages || [];
                options.level = 'info';
                options.icon = 'complete';
                options.windowTopClass = 'fade-out';
                options.animation = false;
                modalOptions = angular.extend({}, provider.modalOptions, defaultOption);
                modalOptions.size = options.size || [600, 120];
                modalOptions.level = options.level;
                if (modalOptions.size && angular.isArray(modalOptions.size)) {
                    options.bodyStyle = {
                        width: modalOptions.size[0] + 'px',
                        height: modalOptions.size[1] + 'px'
                    };
                }
                dialogsInstance = openModalDialogs(modalOptions);
                return dialogsInstance;
            }
            function openJumpDialogs(options) {
                var dialogsInstance, modalOptions, defaultOption = {
                    templateUrl: options.templateUrl || 'fs/template/modal/jump.html',
                    controller: 'messageDialogsController',
                    controllerAs: 'vm',
                    windowTopClass: options.windowTopClass,
                    animation: options.animation === undefined ? true : options.animation,
                    resolve: {
                        dialogsOptions: function () {
                            return options;
                        }
                    }
                };
                options.title = options.title || 'title.dialogs.acknowledge';
                options.messages = options.messages || [];
                options.level = 'info';
                options.icon = 'complete';
                options.windowTopClass = 'fade-out';
                options.animation = false;
                modalOptions = angular.extend({}, provider.modalOptions, defaultOption);
                modalOptions.size = options.size || [600, 120];
                modalOptions.level = options.level;
                if (modalOptions.size && angular.isArray(modalOptions.size)) {
                    options.bodyStyle = {
                        width: modalOptions.size[0] + 'px',
                        height: modalOptions.size[1] + 'px'
                    };
                }
                dialogsInstance = openModalDialogs(modalOptions);
                return dialogsInstance;
            }
            function openErrorDialogs(options) {
                var dialogsInstance;
                options.title = options.title || 'title.dialogs.error';
                options.autoClose = (options.autoClose == true);
                options.autoCloseInterval = options.autoCloseInterval || 3;
                options.level = 'error';
                options.icon = 'failed';
                dialogsInstance = openWarningDialogs(options);
                return dialogsInstance;
            }
            function openInfoDialogs(options) {
                var dialogsInstance;
                options.title = options.title || 'title.dialogs.info';
                options.autoClose = (options.autoClose == true);
                options.autoCloseInterval = options.autoCloseInterval || 3;
                options.level = 'info';
                options.icon = 'regular';
                dialogsInstance = openWarningDialogs(options);
                return dialogsInstance;
            }
            function openSuccessDialogs(options) {
                var dialogsInstance;
                options.title = options.title || 'title.dialogs.success';
                options.autoClose = (options.autoClose == true);
                options.autoCloseInterval = options.autoCloseInterval || 3;
                options.level = 'success';
                options.icon = 'success';
                dialogsInstance = openWarningDialogs(options);
                return dialogsInstance;
            }
            // for log dialog
            function openLogDialogs(options) {
                var dialogsInstance, modalOptions, defaultOption = {
                    templateUrl: options.templateUrl || 'fs/template/modal/logMessages.html',
                    controller: 'messageDialogsController',
                    controllerAs: 'vm',
                    windowTopClass: options.windowTopClass,
                    animation: options.animation === undefined ? true : options.animation,
                    resolve: {
                        dialogsOptions: function () {
                            return options;
                        }
                    }
                };
                options.title = options.title || 'title.dialogs.info';
                options.messages = options.messages || [];
                modalOptions = angular.extend({}, provider.modalOptions, defaultOption);
                modalOptions.level = 'info';
                dialogsInstance = openDialogs(modalOptions);
                return dialogsInstance;
            }
            function openConfirmDialogs(options) {
                var dialogsInstance, modalOptions, defaultOption = {
                    templateUrl: options.templateUrl || 'fs/template/modal/confirmMessages.html',
                    controller: 'messageDialogsController',
                    controllerAs: 'vm',
                    windowTopClass: options.windowTopClass,
                    animation: options.animation === undefined ? true : options.animation,
                    resolve: {
                        dialogsOptions: function () {
                            return options;
                        }
                    }
                };
                options.title = options.title || 'title.dialogs.confirm';
                options.level = options.level || 'info';
                if (options.level == 'info') {
                    options.icon = options.icon || 'regular';
                } else if (options.level == 'warning') {
                    options.icon = options.icon || 'warning';
                } else if (options.level == 'success') {
                    options.icon = options.icon || 'success';
                } else if (options.level == 'error') {
                    options.icon = options.icon || 'failed';
                } else {
                    options.icon = 'failed';
                }
                options.messages = options.messages || [];
                modalOptions = angular.extend({}, provider.modalOptions, defaultOption);
                modalOptions.size = options.size || [600, 120];
                modalOptions.blocked = true;
                if (modalOptions.size && angular.isArray(modalOptions.size)) {
                    options.bodyStyle = {
                        width: modalOptions.size[0] + 'px',
                        height: modalOptions.size[1] + 'px'
                    };
                }
                dialogsInstance = openModalDialogs(modalOptions);
                return dialogsInstance;
            }
            function openPromptDialogs(options) {
                var dialogsInstance, modalOptions, defaultOption = {
                    templateUrl: options.templateUrl || 'fs/template/modal/promptInput.html',
                    controller: 'messageDialogsController',
                    controllerAs: 'vm',
                    windowTopClass: options.windowTopClass,
                    animation: options.animation === undefined ? true : options.animation,
                    resolve: {
                        dialogsOptions: function () {
                            return options;
                        }
                    }
                };
                options.title = options.title || 'title.dialogs.prompt';
                options.messages = options.messages || [];
                options.level = options.level || 'info';
                options.icon = options.icon || 'regular';
                modalOptions = angular.extend({}, provider.modalOptions, defaultOption);
                modalOptions.size = [400, 120];
                modalOptions.blocked = true;
                if (modalOptions.size && angular.isArray(modalOptions.size)) {
                    options.bodyStyle = {
                        width: modalOptions.size[0] + 'px',
                        height: modalOptions.size[1] + 'px'
                    };
                }
                dialogsInstance = openModalDialogs(modalOptions);
                return dialogsInstance;
            }
            function openCustomDialogs(options) {
                var dialogsInstance, modalOptions, dialogsModule, defaultOption, dependentFiles, layoutConfig, i18nConfig, validatorConfig, authorizationConfig;
                var cacheLayout = false, cacheResource = false, cacheAuthorization = false, cacheValidationRule = false;
                dialogsModule = angular.merge({}, provider.dialogsModules[options.dialogsModule]);
                dialogsModule.disableButton = function ($event) {
                    var btn = ($event.srcElement || $event.target).parentElement;
                    if (btn.disabled) {
                        return false;
                    }
                    btn.disabled = true;
                    $timeout(function () {
                        btn.disabled = false;
                    }, 500, false);
                };
                if (dialogsModule.templateUrl) {
                    dialogsModule.templateUrl = dialogsModule.templateUrl.replace('${theme}', routerService.getTheme());
                }
                dependentFiles = dialogsModule.dependentFiles;
                layoutConfig = dialogsModule.layoutConfig;
                i18nConfig = dialogsModule.i18nConfig;
                validatorConfig = dialogsModule.validatorConfig;
                authorizationConfig = dialogsModule.authorizationConfig;
                function getFormValidateMessages(formCtrls) {
                    var errors = {};
                    angular.forEach(formCtrls, function (formCtrl) {
                        if (formCtrl.validateErrors) {
                            angular.merge(errors, formCtrl.validateErrors);
                        }
                        if (formCtrl._formCtrls) {
                            angular.merge(errors, getFormValidateMessages(formCtrl._formCtrls));
                        }
                    });
                    return angular.equals({}, errors) ? null : errors;
                }
                // show error Messages if the form is invalid.
                dialogsModule.showErrorMessages = function (topFormCtrl) {
                    var errors = getFormValidateMessages([topFormCtrl]);
                    if (errors) {
                        openErrorDialogs({
                            'title': '',
                            'messages': errors
                        });
                    }
                };
                dependentFileFn.$inject = ['$ocLazyLoad'];
                function dependentFileFn($ocLazyLoad) {
                    angular.forEach(dependentFiles, function (filePath, index) {
                        dependentFiles[index] = filePath.replace('${theme}', routerService.getTheme());
                    });
                    return $ocLazyLoad.load(dependentFiles, {
                        cache: true
                    });
                }
                layoutConfigFn.$inject = ['$rootScope', '$q', 'ajaxServiceFactory', 'storageService'];
                function layoutConfigFn($rootScope, $q, ajaxServiceFactory, storageService) {
                    var url = layoutConfig, ajaxService, siteInfo, defer = $q.defer();
                    if (!url) {
                        return $q.resolve({});
                    }
                    siteInfo = storageService.getSiteInfo();
                    if (options.params && options.params.siteCode && siteInfo && siteInfo.siteCode && options.params.siteCode != siteInfo.siteCode) {
                        url = url + "/" + options.params.siteCode;
                    }
                    ajaxService = ajaxServiceFactory.buildAjaxService({
                        loadConfig: {
                            'url': url,
                            'method': 'post',
                            'cache': cacheLayout
                        }
                    });
                    var params = {};
                    if (options.params && options.params.parmCat)
                        params.parmCat = options.params.parmCat;
                    if (options.params && options.params.parmSubcat)
                        params.parmSubcat = options.params.parmSubcat;
                    ajaxService.loadConfig(params).then(function (response) {
                        defer.resolve(response ? response.data : {});
                    }, function (error) {
                        log.debug('can not load config[' + url + ']:' + error);
                        defer.reject();
                    });
                    return defer.promise;
                }

                i18nConfigFn.$inject = ['$rootScope', '$q', 'StorageConstants', 'storageService', 'ajaxServiceFactory'];
                function i18nConfigFn($rootScope, $q, StorageConstants, storageService, ajaxServiceFactory) {
                    var ajaxService, defer = $q.defer();
                    if (!i18nConfig) {
                        return $q.resolve({});
                    }
                    ajaxService = ajaxServiceFactory.buildAjaxService({
                        loadConfig: {
                            'url': i18nConfig,
                            'method': 'get',
                            'cache': cacheResource
                        }
                    });
                    ajaxService.loadConfig().then(function (response) {
                        defer.resolve(loadResource($rootScope, StorageConstants.NOTIFY_CHANGE_LANGUAGE, StorageConstants.SESSION_I18N_RESOURES, storageService, response ? response.data : null));
                    }, function error(error) {
                        log.debug('can not load config[' + url + ']:' + error);
                        defer.reject();
                    });

                    return defer.promise;
                }

                authorizationConfigFn.$inject = ['$rootScope', '$q', '$stateParams', 'StorageConstants', 'ajaxServiceFactory'];
                function authorizationConfigFn($rootScope, $q, $stateParams, StorageConstants, ajaxServiceFactory) {
                    var ajaxService, defer = $q.defer();
                    if (!authorizationConfig) {
                        return $q.resolve({});
                    }
                    ajaxService = ajaxServiceFactory.buildAjaxService({
                        loadConfig: {
                            'url': authorizationConfig,
                            'method': 'get',
                            'cache': cacheAuthorization
                        }
                    });
                    ajaxService.loadConfig().then(function (response) {
                        $stateParams.authorization = buildAuthService($rootScope, StorageConstants, ajaxServiceFactory, response ? response.data : {});
                        defer.resolve($stateParams.authorization);
                    }, function error(error) {
                        log.debug('can not load config[' + url + ']:' + error);
                        defer.reject();
                    });
                    return defer.promise;
                }

                validatorConfigFn.$inject = ['$rootScope', '$q', 'StorageConstants', 'storageService', 'ajaxServiceFactory'];
                function validatorConfigFn($rootScope, $q, StorageConstants, storageService, ajaxServiceFactory) {
                    var ajaxService, defer = $q.defer();
                    if (!validatorConfig) {
                        return $q.resolve({});
                    }
                    ajaxService = ajaxServiceFactory.buildAjaxService({
                        loadConfig: {
                            'url': validatorConfig,
                            'method': 'get',
                            'cache': cacheValidationRule
                        }
                    });
                    ajaxService.loadConfig().then(function (response) {
                        var resources = (response && response.data) ? response.data.resources : null;
                        if (resources) {
                            loadResource($rootScope, StorageConstants.NOTIFY_CHANGE_LANGUAGE, StorageConstants.SESSION_I18N_VALIDATION_RESOURES, storageService, resources);
                        }
                        defer.resolve((response && response.data) ? (response.data.rules || {}) : {});
                    }, function error(error) {
                        log.debug('can not load config[' + url + ']:' + error);
                        defer.reject();
                    });

                    return defer.promise;
                }

                function buildAuthService($rootScope, StorageConstants, ajaxServiceFactory, authorizationConfig) {
                    var authorizationServices = {}, authService, emptyServiceNames = [];
                    angular.forEach(authorizationConfig, function (value, key) {
                        if (value == '') {
                            emptyServiceNames.push(key);
                        } else {
                            authorizationServices[key] = {
                                url: 'do/' + value,
                                method: 'post',
                                cache: true
                            };
                        }
                    });
                    authService = ajaxServiceFactory.buildAjaxService(authorizationServices) || {};
                    angular.forEach(emptyServiceNames, function (value, key) {
                        authService[value] = angular.noop;
                    });
                    return authService;
                }

                function loadResource($rootScope, notifyType, resourceType, storageService, resources) {
                    if (resources) {
                        storageService.setItemToSession(resourceType, resources);
                        $rootScope.$emit(notifyType);
                    }
                    return resources;
                }

                options.title = options.title || (dialogsModule.title || 'title.dialogs.lookup');
                options.params = options.params || {};
                options.btnCallback = options.btnCallback || {};
                if (!options.size) {
                    delete options.size;
                }
                angular.merge(dialogsModule, options);
                dialogsModule.size = dialogsModule.size || [800, 500];
                dialogsModule.level = options.level || 'info';
                dialogsModule.icon = options.icon || 'regular';
                if (dialogsModule.size && angular.isArray(dialogsModule.size)) {
                    dialogsModule.bodyStyle = {
                        width: dialogsModule.size[0] + 'px',
                        height: dialogsModule.size[1] + 'px'
                    };
                }
                defaultOption = {
                    templateUrl: options.templateUrl || 'fs/template/modal/custormer.html',
                    size: dialogsModule.size,
                    controller: dialogsModule.controller,
                    controllerAs: dialogsModule.controllerAs,
                    windowTopClass: options.windowTopClass,
                    animation: options.animation === undefined ? true : options.animation,
                    resolve: {
                        dialogsModule: function () {
                            return dialogsModule;
                        },
                        dependentFiles: dependentFileFn,
                        layoutConfig: layoutConfigFn,
                        i18nConfig: i18nConfigFn,
                        authService: authorizationConfigFn,
                        validatorConfig: validatorConfigFn
                    }
                };
                modalOptions = angular.extend({}, provider.modalOptions, defaultOption);
                modalOptions.blocked = true;
                dialogsInstance = openModalDialogs(modalOptions);
                return dialogsInstance;
            }
            return {
                openLoading: openLoading,
                closeLoading: closeLoading,
                openModalDialogs: openModalDialogs,
                openDialogs: openDialogs,
                openAcknowledgeDialogs: openAcknowledgeDialogs,
                openJumpDialogs: openJumpDialogs,
                openWarningDialogs: openWarningDialogs,
                openInfoDialogs: openInfoDialogs,
                openSuccessDialogs: openSuccessDialogs,
                openErrorDialogs: openErrorDialogs,
                openConfirmDialogs: openConfirmDialogs,
                openPromptDialogs: openPromptDialogs,
                openLogDialogs: openLogDialogs,
                openCustomDialogs: openCustomDialogs
            };
        }
    }
})(angular);